package ar.fiuba.tp7552.buildadmin.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class GenericDaoHibernate<T, PK extends Serializable> implements GenericDao<T, PK> {

	 /**
     * Log variable for all child classes. Uses LogFactory.getLog(getClass()) from Commons Logging
     */
    protected final Log log = LogFactory.getLog(getClass());

    public static final String PERSISTENCE_UNIT_NAME = "buildadmin";
    
    /**
     * Entity manager, injected by Spring using @PersistenceContext annotation on setEntityManager()
     */
    @PersistenceContext(unitName=PERSISTENCE_UNIT_NAME)
    private EntityManager entityManager;
    private Class<T> persistentClass;

    public GenericDaoHibernate(final Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public GenericDaoHibernate(final Class<T> persistentClass, EntityManager entityManager) {
        this.persistentClass = persistentClass;
        this.entityManager = entityManager;
    }

    /**
     * retorna el entity manager de JPA.
     * @return
     */
    public EntityManager getEntityManager() {
        return this.entityManager;
    }
    
    /**
     * retorna la sesion de hibernate por si se quiere utilizar
     * las criterias de hibernate en lugar de JPA.
     * @return
     */
    public Session getHibernateSession() {
    	return (Session) this.entityManager.getDelegate();
    }
    
	@Override
	@SuppressWarnings("unchecked")
//	@Transactional
	public Collection<T> getAll() {
		String query =  "select obj from " + this.persistentClass.getName() + " obj";
		return this.entityManager.createQuery(query).getResultList();
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public Collection<T> getAll(List<Long> ids) {
		if (ids == null || ids.size() == 0) {
			return new ArrayList<T>();
		}
		
		Session session = this.getHibernateSession();
		Criteria crit = session.createCriteria(persistentClass)
			.add(Restrictions.in("id", ids));
		return crit.list();
	}

	@Override
	public T get(PK id) {
		T entity = this.entityManager.find(this.persistentClass, id);

        if (entity == null) {
            String msg = "Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...";
            log.warn(msg);
            throw new EntityNotFoundException(msg);
        }
        return entity;
	}

	@Override
//	@Transactional
	public boolean exists(PK id) {
		T entity = this.entityManager.find(this.persistentClass, id);
		 return entity != null;
	}

	@Override
//	@Transactional
	public void save(T object) {
		this.entityManager.persist(object);
	}

	@Override
//	@Transactional
	public void remove(PK id) {
		 this.entityManager.remove(this.get(id));
	}

	@Override
	public void update(T object) {
		this.entityManager.merge(object);
	}
}
